const { Op } = require("sequelize");

const Cart = require("../model/cart.model");
const Goods = require("../model/goods.model");

class CartService {
  async createOrUpdate(user_id, goods_id) {
    /**
     * findOne方法：查找满足条件的第一条数据
     * 通常返回模型实例的方法：单条记录查询/创建（如：create、findOne、findByPk等）或实例自身的更新方法（如：实例调用的 save()、update()、increment() 等方法）
     */
    const res = await Cart.findOne({
      where: {
        /**
         * 查询条件需要同时满足 user_id = user_id 和 goods_id = goods_id
         * Op.and 是 Sequelize 的查询操作符，用于构建 AND 逻辑条件。
         * Sequelize 提供了多种运算符，除了 Op.and 运算符之外，还有 Op.eq, Op.or, Op.is, Op.not 等等。
         *
         * Op 运算符的使用场景：当查询条件包含嵌套逻辑时，当部分查询需要复杂逻辑时，对于团队协作或复杂项目，显式使用 [Op.and] 可以让代码风格更统一。
         */
        [Op.and]: {
          user_id,
          goods_id,
        },
      },
    });
    // 若该用户已经存在一条goods_id的记录，则数量加一
    if (res) {
      /**
       * 存在记录就给购物车商品的数量加1
       * 调用模型实例 res 的内置方法 increment 给当前实例的 number 字段的值 +1，并直接更新到数据库
       * res.increment("number"); 等价于 res.increment("number", { by: 1 }); ，只增加 1 时, 可以省略 'by' 参数。
       */
      await res.increment("number");
      /**
       * 调用模型实例的 reload 方法从数据库重新加载最新数据并更新实例
       * 确保返回的实例包含最新的字段值（如 updatedAt 等自动维护的字段）
       */
      return await res.reload();
    } else {
      // 若该用户没有goods_id的记录，则创建一条。这里只需指定 user_id 和 goods_id 的值，其他的字段会有默认值或会自增
      return await Cart.create({
        user_id,
        goods_id,
      });
    }
  }
  /**
   * 分页查询购物车列表
   * @param {number} pageNum - 页码（从1开始）
   * @param {number} pageSize - 每页显示数量
   * @returns {Promise<Object>} 包含分页信息和购物车列表的对象
   */
  async findCarts(pageNum, pageSize) {
    // 将传入的参数转为数字类型，避免字符串导致计算错误
    pageNum = pageNum * 1;
    pageSize = pageSize * 1;
    // 计算分页偏移量（跳过前面多少条数据）
    const offset = (pageNum - 1) * pageSize;
    const { count, rows } = await Cart.findAndCountAll({
      offset: offset, // 分页偏移量
      limit: pageSize, // 每页最大记录数
      attributes: ["id", "number", "selected"], // 指定只查询当前表里的哪些字段
      include: {
        model: Goods, // 将 Goods 模型关联进查询中（除了查询当前表之外，还要去查询 zd_goods 表）
        as: "goods_info", // 使用定义的关联别名，需与模型中关联配置的as保持一致
        attributes: ["id", "goods_name", "goods_price", "goods_img"], // 指定只查询关联表（zd_goods表）里的哪些字段
      },
    });
    const result = {
      pageNum,
      pageSize,
      total: count,
      list: rows,
    };
    return result;
  }
  /**
   * 更新购物车项
   * @param {number} id 购物车项id
   * @param {number} number 购物车项的数量
   * @param {boolean} selected 购物车项的选择状态
   */
  async updateCart(params) {
    const { id, number, selected } = params;
    // 根据主键从表中查询一条数据
    const res = await Cart.findByPk(id);
    // 没找到数据
    if (!res) {
      return "";
    }
    // 更新数据
    number !== undefined ? (res.number = number) : "";
    selected !== undefined ? (res.selected = selected) : "";
    // 保存更新，返回更新后的结果
    return await res.save();
  }
  /**
   * 批量删除购物车记录
   * @param {Array<number>} ids - 要删除的购物车记录ID数组（每个元素为zd_carts表的主键id）
   * @returns {Promise<number>} 删除成功的记录数量（Sequelize的destroy方法会返回受影响的行数）
   * @description
   * 1. 使用Sequelize的destroy方法执行批量删除，通过Op.in操作符匹配ids数组中的所有ID
   * 2. 仅删除zd_carts表中id在ids数组内的记录，不会自动关联删除其他表数据（如关联的zd_goods表）
   * 3. 若ids为空数组，会返回0（无记录被删除），不会报错
   * 4. 需确保传入的ids为有效数字数组，避免因类型错误导致删除失败
   */
  async removeCarts(ids) {
    // 批量删除zd_carts表中id在ids数组内的记录
    return await Cart.destroy({
      where: {
        id: {
          [Op.in]: ids, // Op.in表示"在...范围内"，匹配所有id属于ids数组的记录
        },
      },
    });
  }
  /**
   * 批量更新当前用户购物车项的选中状态（全选/取消全选）
   * @param {number} user_id - 用户ID（用于限定操作当前用户的购物车，避免越权）
   * @param {boolean} selected - 目标选中状态（true为全选，false为取消全选）
   * @returns {Promise<number[]>} Sequelize返回的数组，第一个元素为受影响的行数（更新成功的记录数）
   * @description
   * 1. 功能：根据user_id定位用户，将其所有购物车项的selected字段更新为指定值
   * 2. 逻辑：仅更新当前用户的购物车数据（通过where条件中的user_id过滤）
   * 3. 注意：
   *    - 若用户无购物车项，返回[0]（无记录被更新）
   *    - selected必须为布尔值（true/false），否则可能导致更新失败
   *    - 该操作是幂等的（多次调用相同参数，结果一致）
   */
  async batchSelectedCarts(user_id, selected) {
    return await Cart.update(
      { selected: selected },
      {
        where: {
          user_id, // 仅更新当前用户的购物车
        },
      },
    );
  }
  async queryTotalCarts(user_id) {
    const count = await Cart.count({
      where: {
        user_id, // 仅获取当前用户的购物车
      },
    });
    const result = {
      total: count,
    };
    return result;
  }
}

module.exports = new CartService();
